02 Differential Connectomics.Rmd
Connectome
can be used to identify and visualize major perturbed cell-cell communication pathways in A:B comparisons of complex tissue systems.
To demonstrate differential connectomics using Connectome
, we will use the interferon-stimulated vs. control PBMC data distributed by SeuratData:
InstallData('ifnb') data('ifnb') table(Idents(ifnb)) #> #> IMMUNE_CTRL IMMUNE_STIM #> 6548 7451 Idents(ifnb) <- ifnb[['seurat_annotations']] table(Idents(ifnb)) #> #> CD14 Mono CD4 Naive T CD4 Memory T CD16 Mono B #> 4362 2504 1762 1044 978 #> CD8 T T activated NK DC B Activated #> 814 633 619 472 388 #> Mk pDC Eryth #> 236 132 55
Connectomic networks must first be calculated for each tissue system separately. To do so:
# First identify ligands and receptors which have mapped in the dataset: connectome.genes <- union(Connectome::ncomms8866_human$Ligand.ApprovedSymbol,Connectome::ncomms8866_human$Receptor.ApprovedSymbol) genes <- connectome.genes[connectome.genes %in% rownames(ifnb)] # Split the object by condition: ifnb.list <- SplitObject(ifnb,split.by = 'stim') # Normalize, Scale, and create Connectome: ifnb.con.list <- list() for (i in 1:length(ifnb.list)){ ifnb.list[[i]] <- NormalizeData(ifnb.list[[i]]) ifnb.list[[i]] <- ScaleData(ifnb.list[[i]],features = rownames(ifnb.list[[i]])) ifnb.con.list[[i]] <- CreateConnectome(ifnb.list[[i]],species = 'human',p.values = F) } names(ifnb.con.list) <- names(ifnb.list)
The two global signaling networks can then be directly compared. Here, we do so using the function DifferentialConnectome
. For this functon to run, the two systems must be parcellated in exactly the same way (the same cell types must be present in both) and the rownames (genes) of the original DGE matrices must be identical.
diff <- DifferentialConnectome(ifnb.con.list[[1]],ifnb.con.list[[2]])
Because we are dealing with single-cell data, we can leverage the data structure to identify which ligands and receptors, in which cell populations, have changed in a statistically significant fashion. One way to do this:
# Stash idents and make new identities which identify each as stimulated vs. control celltypes <- as.character(unique(Idents(ifnb))) celltypes.stim <- paste(celltypes, 'STIM', sep = '_') celltypes.ctrl <- paste(celltypes, 'CTRL', sep = '_') ifnb$celltype.condition <- paste(Idents(ifnb), ifnb$stim, sep = "_") ifnb$celltype <- Idents(ifnb) Idents(ifnb) <- "celltype.condition" # Identify which ligands and receptors, for which cell populations, have an adjusted p-value < 0.05 based on a Wilcoxon rank test diff.p <- data.frame() for (i in 1:length(celltypes)){ temp <- FindMarkers(ifnb, ident.1 = celltypes.stim[i], ident.2 = celltypes.ctrl[i], verbose = FALSE, features = genes, min.pct = 0, logfc.threshold = 0) temp2 <- subset(temp, p_val_adj < 0.05) if (nrow(temp2)>0){ temp3 <- data.frame(genes = rownames(temp2),cells = celltypes[i]) diff.p <- rbind(diff.p, temp3) } } diff.p$cell.gene <- paste(diff.p$cells,diff.p$genes,sep = '.') # Filter differential connectome to only include significantly perturbed edges diff$source.ligand <- paste(diff$source,diff$ligand,sep = '.') diff$target.receptor <- paste(diff$target,diff$receptor,sep = '.') diff.sub <- subset(diff,source.ligand %in% diff.p$cell.gene & target.receptor %in% diff.p$cell.gene)
Differential connectomics are challenging to visualize, because every differential edge takes data from 4 places: the ligand expression in both the control and test condition, and the receptor expression in the control and test condition. Further, a single ligand can hit multiple receptors and vice-versa. One way to visualize this data is with edge-aligned heatmaps. Here, we use the function DifferentialScoringPlot
to create three aligned heatmaps: one showing the ligand log fold change, one showing the receptor log fold change, and one showing a ‘perturbation score’ which is the product of the absolute values of the data in the first two plots. This helps to identify those edges which both pass the desired expression thresholds in at least one of the systems, and are highly perturbed in the A:B comparison.
DifferentialScoringPlot(diff.sub,min.score = 1,min.pct = 0.1,infinity.to.max = T)
Since the above plot is not particularly concise, we have built DifferentialCircos
, which draws circos plots for a differential connectome. This plot type makes use of the perturbation score, which is always positive, by design. However, in conenctomic data, there are 4 separate classes of perturbations, as both the ligand and the receptor can either be differentially increased or decreased. Here, we look at the above edgelist (which is shown in full in the DifferentialScoringPlot) and investigate each type of perturbation in turn:
diff.up.up <- subset(diff.sub,ligand.norm.lfc > 0 & recept.norm.lfc > 0 ) CircosDiff(diff.up.up,min.score = 2,min.pct = 0.1,lab.cex = 0.4)
diff.up.down <- subset(diff.sub,ligand.norm.lfc > 0 & recept.norm.lfc < 0 ) CircosDiff(diff.up.down,min.score = 2,min.pct = 0.1,lab.cex = 0.4)
diff.down.up <- subset(diff.sub,ligand.norm.lfc < 0 & recept.norm.lfc > 0 ) CircosDiff(diff.down.up,min.score = 2,min.pct = 0.1,lab.cex = 0.4)
diff.down.down <- subset(diff.sub,ligand.norm.lfc < 0 & recept.norm.lfc < 0 ) CircosDiff(diff.down.down,min.score = 2,min.pct = 0.1,lab.cex = 0.4)
We can also use DifferentialCircos
to quantify edge perturbation within a specific subset or community of cells:
CircosDiff(diff.sub,min.score = 2,min.pct = 0.1,lab.cex = 0.4, sources.include = c('pDC','CD8 T','B'),targets.include = c('CD16 Mono','CD14 Mono'))
By subsetting to only those edges falling on a specific cell type, we can quantify the effect of a systemic perturbation (in this specific case, interferon treatment) on a given cellular niche:
CircosDiff(diff.sub,min.score = 2,min.pct = 0.1,lab.cex = 0.4, targets.include = c('CD14 Mono'))
Since the above plot is still somehwat complex, we can further focus on the network landing on a single receptor, on a single cell type:
CircosDiff(diff.sub,min.score = 2,min.pct = 0.1,lab.cex = 0.6, targets.include = c('CD14 Mono'),features = c('CCR5'))